﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using CafeOnline.MvcFramework.Interfaces;
using CafeOnline.MvcFramework.Web.Json;

namespace CafeOnline.MvcFramework.Grid {
    public class GridBase : IGrid {
        #region IFields

        private CallGrid m_grid;
        private readonly string m_id;
        private readonly string m_gridType;
        private readonly GridCustomSettings m_columnSettings;

        #endregion IFields
        #region IProperties

        public GridCustomSettings CustomSettings {
            get {
                return m_columnSettings;
            }
        }

        public string ID {
            get {
                return m_id;
            }
        }

        public string Type {
            get;
            set;
        }

        public GridOptions Options {
            get;
            private set;
        }

        public IEnumerable<Column> CurrentColumns {
            get {
                return m_grid.Columns;
            }
        }

        public IEnumerable<IColumnFactory> AllColumnFactory {
            get;
            set;
        }

        public bool HasFooterData {
            get;
            private set;
        }

        #endregion IProperties
        #region IConstructors

        public GridBase(string gridType, string gridId, IEnumerable<IColumnFactory> columns, GridCustomSettings customSettings) {
            m_id = gridId;
            m_gridType = gridType;
            AllColumnFactory = columns;
            m_columnSettings = customSettings;
        }

        #endregion IConstructors
        #region IMethods

        public void Initialize(GridOptions options) {
            Options = options;
            HasFooterData = options.Toolbar;
            m_grid = (CallGrid)new CallGrid(m_gridType, m_id)
                    .setAutoWidth(true)
                    .setMultiSelect(options.MultiSelect)
                    .setHeaderTitles(options.HeaderTitles)
                    .setHideColumnHeaders(options.HideColumnHeaders)
                    .setHideGrid(false)
                    .setGridView(false)
                    .setSearchToolbar(options.Searchable)
                    .setSearchOnEnter(options.SearchOnEnter)
                    .setColumnSelector(options.ColumnSelector)
                    .setScroll(options.Scroll)
                    .setToolbar(options.Toolbar)
                    .setEditButtons(options.EditButton)
                    .setDeleteButtons(options.DeleteButton).onSelectRow(options.OnSelect).setUserDataOnFooter(options.FooterData);

            m_grid.setUrl(VirtualPathUtility.ToAbsolute(String.Format("~/Grid/GetData/?gridType={0}&gridID={1}",
                                                            m_gridType, m_id)));
            m_grid.Ctx = options.Ctx;

            JavascriptFunction jf =
                new JavascriptFunction(
                    "var colModel = $('#{0}').jqGrid('getGridParam','colModel');$.post('{2}',{{column: colModel[index].name, width: newwidth, gridId: '{0}', gridType : '{1}'}});",
                    m_id, m_gridType, VirtualPathUtility.ToAbsolute(String.Format("~/Grid/SetColumnWidth")));
            m_grid.onResizeStop(jf);
            m_grid.setCaption(options.NoSubGrid ? null : options.Caption);
            if (options.Toolbar) {
                m_grid = (CallGrid)m_grid.setToolbar(true).setToolbarPosition(ToolbarPosition.top);
            }

            if (options.Pager) {
                m_grid = (CallGrid)m_grid.setPager("pager_" + m_id).setViewRecords(true).setRowList(new int[] { 10, 15, 20, 50 });
            }

            if (options.RowNumber > 0) {
                m_grid = (CallGrid)m_grid.setRowNum(options.RowNumber);
            }

            if (options.AdditionalSettings != null) {
                options.AdditionalSettings(m_grid);
            }

            if (options.NoSubGrid) {
                m_grid.setSubGrid(null);
            }

            var c = new List<Tuple<IColumnFactory, ColumnCustomSettings>>();
            m_columnSettings.Columns.ForEach(t => {
                if (t.Visible) {
                    List<IColumnFactory> cols = AllColumnFactory.Where(fact => fact.Metadata.ColumnName == t.Name).ToList();
                    // for a given column, it can happen that there are some settings stored in DB
                    // but the column is not present in the grid because the user has no rights for it
                    if (cols.Count > 0) {
                        var f = cols.First();
                        if (t.Order == 0) {
                            t.Order = f.Metadata.Order;
                        }
                        c.Add(new Tuple<IColumnFactory, ColumnCustomSettings>(f, t));
                    }
                }
            });

            RebuildColumns(c, false);
            var jsonReader = new ObjectOptions();
            jsonReader.Add("root", "rows");
            jsonReader.Add("id", "id");
            jsonReader.Add("repeatitems", false);
            if (options.FooterData) {
                jsonReader.Add("userdata", "userdata");
            }
            m_grid.Add("jsonReader", jsonReader);
        }

        public JavaScriptResult ReloadGrid() {
            return m_grid.GetScript();
        }

        public void RefreshColumn(List<string> visibleColumns) {
            var c = new List<Tuple<IColumnFactory, ColumnCustomSettings>>();
            int invisibleOrder = visibleColumns.Count;
            m_columnSettings.Columns.ForEach(t => {
                int index = visibleColumns.IndexOf(t.Name);
                t.Visible = index >= 0;
                if (t.Visible) {
                    t.Order = index + 1;
                    var f = AllColumnFactory.First(fact => fact.Metadata.ColumnName == t.Name);
                    c.Add(new Tuple<IColumnFactory, ColumnCustomSettings>(f, t));
                } else {
                    t.Order = invisibleOrder++;
                }
            });

            RebuildColumns(c, true);
        }

        private void RebuildColumns(List<Tuple<IColumnFactory, ColumnCustomSettings>> factories, bool refresh) {
            m_grid.Columns.Clear();
            factories.Sort(delegate(Tuple<IColumnFactory, ColumnCustomSettings> x, Tuple<IColumnFactory, ColumnCustomSettings> y) {
                return x.Item2.Order.CompareTo(y.Item2.Order);
            });
            factories.ForEach(f => {
                var column = f.Item1.Create(m_id);
                if (f.Item2.Width.HasValue) {
                    column.SetWidth(f.Item2.Width.Value);
                }
                column.SetHidden(!f.Item2.Visible);
                m_grid.addColumn(column);
            });

            Options.ConfigureColumns(m_grid.Columns);
            if (refresh) {
                m_grid.RefreshColumn();
            }
        }

        public void SetColumnWidth(string columnName, int width) {
            var currentCol = m_columnSettings.Columns.First(t => t.Name.Equals(columnName));
            if (currentCol != null) {
                currentCol.Width = width;
                CurrentColumns.First(t => t.ColumnName.Equals(columnName)).SetWidth(width);
            }
        }


        #endregion IMethods
        #region IHtmlString Members

        public string ToHtmlString() {
            return m_grid.ToHtmlString();
        }

        #endregion
    }
}
